<template>
    <div>
        <el-button class="upload-btn" type="info" plain  @click="selectFile">{{uploadTile}}
            <i class="upload-li el-file-upload el-file--left"></i>
        </el-button>

        <input :id="inputId+'-file'" ref="file" class="fileInput" type="file" v-on:change="uploadSource()"/>

    </div>
</template>

<script>
    export default {
        name: "BigFile",
        //暴露出可配置的属性
        props: {
            //暴露按钮标题
            uploadTile: {
                default: '上传大文件'
            },
            //暴露页面中的inputId
            inputId: {
                default: 'upload-source'
            },
            //暴露页面传入的文件类型
            suffixType: {
                default: []
            },
            //暴露接收uniId
            uniId: {
                default: ''
            },
            //接收枚举类型
            useType: {
                default: ''
            },
            //回调函数，组件中没有employee对象
            afterUpload: {
                type: Function,
                default: null
            },
            //增加VOD上传需要配置的参数
            shardSize:{
                default:1024*1024,
            },
            //VOD上唇地址：调用后端服务地址
            url:{
                default:"oss/append",
            }
        },
        data: function () {
            return {}
        },
        methods: {
            selectFile() {
                $("#" + this.inputId + "-file").trigger("click");
            },
            uploadSource() {
                let _this = this;
                //表单方式提交数据
                //let formData=new window.FormData();
                //通过别名获取file，不需要id
                let file = _this.$refs.file.files[0];
                /** 文件唯一标识生成
                 * 方法一：将shard_key=传入的file-dataForm中的name+contentType+size（每次上传文件，这些值是相同的）
                 * 方法二：使用md5摘要算法（对file数据中不变的参数进行封装，file的数据不变，md5值不变）
                 * |- 生成128位二进制数，每4个二进制可以转换为1个16进制，result=32个16进制数
                 * md5十六进制key：d41d8cd98f00b204e9800998ecf8427e
                 * 十进制key：2.8194976848941264e+38
                 * 六十二进制key：6sfSqfOwzmik4A4icMYuUe
                 * hex_md5加入，如果直接写file，就直接使用md_10to64,这里需要拼file(file.name+file.size+file.type)
                 */
                let shardKey16 = hex_md5(file.name + file.size + file.type); //md5:16进制处理file
                let shardKey10 = parseInt(shardKey16, 16);//转换为10进制
                //62进制(短key)：26个大写字母+26个小写字母+10个阿拉伯数字
                let shardKey62 = Tool.md_10to64(shardKey10);
                //file类型判断["jpg","jpeg","png","gif"]
                let suffixType = this.suffixType;
                let fileName = file.name;
                //查询到包含.的索引位置+1，substring提取字符串中介于两个指定下标之间的字符,length-(indexof+1) 转换为小写
                let suffix = fileName.substring(fileName.lastIndexOf(".") + 1, fileName.length).toLowerCase();
                //定义后缀校验变量
                let validateSuffix = false;
                //循环后缀类型
                for (let i = 0; i < suffixType.length; i++) {
                    if (suffixType[i].toLowerCase() === suffix) {
                        validateSuffix = true;
                        break;
                    }
                }
                if (!validateSuffix) {
                    toast.warning("文件格式不正确，只支持上传：" + suffixType.join(",") + "文件");
                    //在拦截后，避免onchange事件不触发，需要清空id标签
                    $("#" + this.inputId + "-file").val("");
                    return;
                }

                //文件分片shard
                let shardSize = _this.shardSize; //每1MB为一个分片，
                let startIndex = 1; //分片起始索引，1为第一个分片
                let size = file.size;//文件大小
                let shardTotal = Math.ceil(size / shardSize);//分片总数，向上取整1.1=2
                let contentType = file.type;
                /**
                 * 统一请求参数，使用formData传递，需要将file中的shardFile转为base64的字符串string
                 * fileReader加载时，接收参数e,转为base64 = e.target.result
                 * base64字符串：文件说明+","+base64码(文件内容)
                 * 在fileReader包裹后，需要_this=this;
                 */
                let param = {
                    //'shard':base64, //进入fileReader后赋值，将转换shardFile的base64字符串传入
                    'size': size,
                    'shardIndex': startIndex,
                    'shardSize': shardSize,
                    'shardTotal': shardTotal,
                    'name': file.name,
                    'suffix': suffix,
                    'shardKey': shardKey62,
                    'contentType': contentType,
                    'moduleId': _this.uniId,
                    'useType': _this.useType
                };
                //上传之前，先检查分片
                _this.checkShardKey(param);
                //_this.upload(param);

            },
            upload: function (param) {
                let _this = this;
                let shardTotal = param.shardTotal;
                let shardIndex = param.shardIndex;
                let shardSize = param.shardSize;
                let shardFile = _this.getShardFile(shardIndex, shardSize);
                //获取input中选择file
                let fileReader = new FileReader();
                //发送请求之前，显示progress进度条
                Progress.show(parseInt((shardIndex - 1) * 100 / shardTotal));
                //先加载fileReader，读取到e，再进行数据shardFile转换
                fileReader.onload = function (e) {
                    let base64 = e.target.result;
                    //使用requestBody传参，先定义js对象，添加进度条取消loadings
                    param.shard = base64;
                    //Loadings.show();
                    //原文件上传本地磁盘
                    //_this.$axios.post(process.env.VUE_APP_SERVER + '/source/admin/upload/bigfile', param)
                    //OSS上传
                    _this.$axios.post(process.env.VUE_APP_SERVER + '/source/client/'+_this.url, param)
                        .then((response) => {
                            let resp = response.data;
                            //请求成功，更新进度条，上传完第1个分片，显示对应%
                            Progress.show(parseInt(shardIndex * 100 / shardTotal));
                            //判断分片的shardIndex和shardTotal值，是否分片上传完毕
                            if (shardIndex < shardTotal) {
                                //上传下一个分片
                                param.shardIndex = param.shardIndex + 1;
                                //测试断网情况，断点续传
                                /*if(param.shardIndex===3){
                                    return;
                                }*/
                                //自调用，再次根据param递归上传
                                _this.upload(param);
                            } else {
                                //上传完毕，关闭进度条
                                Progress.hide();
                                //将获取的resp放入回调，传到页面
                                _this.afterUpload(resp);
                                //避免on-change事件在第二次相同类型点击后，不触发，将id对应标签设置为空.
                                $("#" + _this.inputId + "-file").val("");
                            }

                        });
                }
                //需要放在fileReader之后，生成shardFile
                fileReader.readAsDataURL(shardFile);
            },
            getShardFile: function (shardIndex, shardSize) {
                let _this = this;
                //通过别名获取file，不需要id
                // 这里第3次获取不到file，需要将$("#" + _this.inputId + "-file").val("");放在else=》afterUpload之后
                let file = _this.$refs.file.files[0];
                let start = (shardIndex - 1) * shardSize; //分片起始大小
                //分片结束位置:获取文件大小，取最小值，当20+10=30大于文件大小时，结束位置选min
                let end = Math.min(file.size, start + shardSize);
                //从start→end截取当前的分片数据
                let shardFile = file.slice(start, end);
                return shardFile;
            },
            checkShardKey(param) {
                let _this = this;
                _this.$axios.get(process.env.VUE_APP_SERVER + '/source/client/oss/check/file/' + param.shardKey)
                    .then((response) => {
                        let resp = response.data;
                        //判断分片的shardIndex和shardTotal值，是否分片上传完毕
                        if (resp.success) {
                            //获取fileDto
                            let fileDto = resp.responseData;
                            if (!fileDto) {
                                param.shardIndex = 1;
                                //根据param递归上传
                                _this.upload(param);
                            } else if (fileDto.shardIndex === fileDto.shardTotal) {
                                toast.success("文件急速秒传成功！");
                                _this.afterUpload(resp);
                                //清空input-id
                                $("#" + _this.inputId + "-file").val("");
                            } else {
                                param.shardIndex = fileDto.shardIndex + 1;
                                _this.upload(param);
                            }

                        } else {
                            toast.warning("操作异常，请联系管理员！");
                            $("#" + _this.inputId + "-file").val("");
                        }

                    });
            },
        }
    }
</script>

<style scoped>
    .fileInput {
        margin-left: -300px;
        color: white;
        z-index: -1;
    }

    .upload-btn {
        float: left;
        margin-right: 100%;
        margin-bottom: 10px;
        padding: 8px 8px;
    }

    .upload-li {
        font-size: 20px;
    }

</style>